package com.yunkeji.api.moments.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.cache.LoadingCache;
import com.yunkeji.api.moments.bo.MomentsListBo;
import com.yunkeji.api.moments.bo.MomentsReplyBo;
import com.yunkeji.api.moments.bo.PubMomentsBo;
import com.yunkeji.api.moments.bo.ReplyListBo;
import com.yunkeji.api.moments.mapper.ApiMomentsMapper;
import com.yunkeji.api.moments.mapper.ApiMomentsReplyMapper;
import com.yunkeji.api.moments.service.MomentsService;
import com.yunkeji.api.moments.vo.MomentsListVo;
import com.yunkeji.api.moments.vo.ReplyVo;
import com.yunkeji.common.constant.CacheConstants;
import com.yunkeji.common.core.page.TableDataInfo;
import com.yunkeji.common.exception.AppServiceException;
import com.yunkeji.common.helper.LoginHelper;
import com.yunkeji.common.msg.PushMessage;
import com.yunkeji.common.msg.bo.PrivateMsg;
import com.yunkeji.common.msg.utils.BadWordDetectorUtils;
import com.yunkeji.dao.domain.*;
import com.yunkeji.dao.mapper.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

@RequiredArgsConstructor
@Service
public class MomentsServiceImpl implements MomentsService {
    private final AppUserMapper appUserMapper;
    private final AppUserExtMapper appUserExtMapper;
    private final UserFocusMapper userFocusMapper;

    private final ApiMomentsMapper apiMomentsMapper;
    private final ApiMomentsReplyMapper apiMomentsReplyMapper;

    private final MomentsReplyMapper momentsReplyMapper;
    private final MomentsLikeMapper momentsLikeMapper;
    private final MomentsReplyLikeMapper momentsReplyLikeMapper;

    @Resource(name = "sensitiveWordCheck")
    LoadingCache<String, BadWordDetectorUtils> sensitiveWordCheck;
    /**
     * 朋友圈列表
     *
     * @author 老张
     */
    @Override
    public TableDataInfo<MomentsListVo> momentsList(MomentsListBo bo) {
        //        if (bo.getType() == 4) {
        //            // 类型 1推荐 2关注 3指定查看某人 4我自己的
        //            bo.setUid(LoginHelper.getUserId());
        //        }
        Page<MomentsListVo> moments =
                apiMomentsMapper.getDefaultMoments(bo.build(), bo, LoginHelper.getUserId());
        return TableDataInfo.build(moments);
    }

    /**
     * 发布朋友圈
     *
     * @author 老张
     */
    @Override
    @SneakyThrows
    public void pubMoments(PubMomentsBo pubMomentsBo) {
        Long aLong =
                apiMomentsMapper.selectCount(
                        Wrappers.lambdaQuery(Moments.class)
                                .ge(Moments::getCreateTime, DateUtil.beginOfDay(new Date()))
                                .le(Moments::getCreateTime, DateUtil.endOfDay(new Date()))
                                .eq(Moments::getUserId, LoginHelper.getUserId()));
        if (aLong >= 3) {
            throw AppServiceException.paramException("每天只能发送三次动态");
        }

        checkKeyWord(pubMomentsBo.getContent());
        AppUser user = appUserMapper.selectById(LoginHelper.getUserId());
        // 插入动态
        Moments moments = BeanUtil.toBean(pubMomentsBo, Moments.class);
        moments.setSex(user.getSex());
        moments.setUserId(LoginHelper.getUserId());
        moments.setPlatformId(LoginHelper.getPlatformId());
        // 插入动态图片
        AppUserExt appUserExt = appUserExtMapper.selectById(LoginHelper.getUserId());
        // 朋友圈附近功能通过这儿实现
        moments.setCityId(appUserExt.getLiveCity());
        moments.setProvinceId(appUserExt.getLiveProvince());
        apiMomentsMapper.insert(moments);
        // 个人信息相册由动态发布的图片实现,显示最新的五张
        List<String> momentsPics = appUserExt.getMomentsPics();
        if (!CollectionUtil.isEmpty(pubMomentsBo.getPics())) {
            if (CollectionUtil.isEmpty(momentsPics)) {
                momentsPics = new LinkedList<>();
            }
            // 最新的到数组最后边
            CollectionUtil.reverse(momentsPics);
            // 把新发布的动态加入到集合
            momentsPics.addAll(pubMomentsBo.getPics());
            // 再次颠倒数组,最新发布的在最前边
            CollectionUtil.reverse(momentsPics);
            // 只显示最新的5张
            List<String> newPics = CollectionUtil.sub(momentsPics, 0, 3);
            appUserExt.setMomentsPics(newPics);
            appUserExtMapper.updateById(appUserExt);
        }
    }

    /**
     * 删除动态
     *
     * @author 老张
     * @param baseId
     */
    @Override
    public void delMoments(BaseId baseId) {
        Moments moments =
                apiMomentsMapper.selectOne(
                        Wrappers.lambdaQuery(Moments.class)
                                .eq(Moments::getId, baseId.getId())
                                .eq(Moments::getUserId, LoginHelper.getUserId()));
        if (moments == null) {
            throw AppServiceException.paramException("数据未找到");
        }
        // 级联删除,会删除下面所有的回复
        apiMomentsMapper.deleteById(baseId.getId());
    }

    /**
     * 删除回复
     *
     * @author 老张
     * @param baseId
     */
    @Override
    public void delReply(BaseId baseId) {
        MomentsReply momentsReply =
                momentsReplyMapper.selectOne(
                        Wrappers.lambdaQuery(MomentsReply.class)
                                .eq(MomentsReply::getId, baseId.getId())
                                .eq(MomentsReply::getUserId, LoginHelper.getUserId()));
        if (momentsReply == null) {
            throw AppServiceException.paramException("动态回复未找到");
        }
        // 级联删除点赞记录
        momentsReplyMapper.deleteById(baseId.getId());
    }

    /**
     * 点赞动态
     *
     * @author 老张
     * @param baseId
     */
    @Override
    public void likeMoments(BaseId baseId) {
        Moments moments = apiMomentsMapper.selectById(baseId.getId());
        if (moments == null) {
            throw AppServiceException.paramException("动态未找到");
        }
        MomentsLike momentsLike =
                momentsLikeMapper.selectOne(
                        Wrappers.lambdaQuery(MomentsLike.class)
                                .eq(MomentsLike::getMomentsId, baseId.getId())
                                .eq(MomentsLike::getFromId, LoginHelper.getUserId()));
        if (momentsLike != null) {
            // 取消点赞
            momentsLikeMapper.delete(
                    Wrappers.lambdaQuery(MomentsLike.class)
                            .eq(MomentsLike::getMomentsId, baseId.getId())
                            .eq(MomentsLike::getFromId, LoginHelper.getUserId()));
            apiMomentsMapper.subLikes(baseId.getId());
        } else {
            // TODO 发布通知
            if (!LoginHelper.getPlatformId().equals(moments.getPlatformId())) {
                AppUserExt appUserExt = appUserExtMapper.selectById(LoginHelper.getUserId());

                PushMessage.sendTextSingleSysSquare(
                        moments.getPlatformId(),
                        PrivateMsg.builder()
                                .content("您收到一条新的点赞")
                                .nickname(appUserExt.getNickName())
                                .headUrl(appUserExt.getHeadUrl())
                                .id(appUserExt.getId())
                                .platformId(LoginHelper.getPlatformId())
                                .build());
            }
            // 点赞
            momentsLike = new MomentsLike();
            momentsLike.setFromId(LoginHelper.getUserId());
            momentsLike.setPlatformId(LoginHelper.getPlatformId());
            momentsLike.setMomentsId(baseId.getId());
            momentsLikeMapper.insert(momentsLike);
            apiMomentsMapper.addLikes(baseId.getId());
        }
    }

    /**
     * 点赞回复
     *
     * @author 老张
     * @param baseId
     */
    @Override
    public void likeReply(BaseId baseId) {
        MomentsReply momentsReply = apiMomentsReplyMapper.selectById(baseId.getId());
        if (momentsReply == null) {
            throw AppServiceException.paramException("动态回复未找到");
        }
        MomentsReplyLike momentsReplyLike =
                momentsReplyLikeMapper.selectOne(
                        Wrappers.lambdaQuery(MomentsReplyLike.class)
                                .eq(MomentsReplyLike::getReplyId, baseId.getId())
                                .eq(MomentsReplyLike::getFromId, LoginHelper.getUserId()));
        if (momentsReplyLike != null) {
            // 取消点赞
            momentsReplyLikeMapper.delete(
                    Wrappers.lambdaQuery(MomentsReplyLike.class)
                            .eq(MomentsReplyLike::getReplyId, baseId.getId())
                            .eq(MomentsReplyLike::getFromId, LoginHelper.getUserId()));

            apiMomentsReplyMapper.subLikes(baseId.getId());
        } else {
            // 点赞
            momentsReplyLike = new MomentsReplyLike();
            momentsReplyLike.setFromId(LoginHelper.getUserId());
            momentsReplyLike.setReplyId(baseId.getId());
            momentsReplyLikeMapper.insert(momentsReplyLike);
            apiMomentsReplyMapper.addLikes(baseId.getId());
        }
    }

    /**
     * 回复动态
     *
     * @author 老张
     */
    @Override
    public void replyMoments(MomentsReplyBo bo) {
        Moments moments = apiMomentsMapper.selectById(bo.getId());
        if (moments == null) {
            throw AppServiceException.paramException("动态未找到");
        }

        checkKeyWord(bo.getContent());

        MomentsReply momentsReply = new MomentsReply();
        momentsReply.setPlatformId(LoginHelper.getPlatformId());
        momentsReply.setUserId(LoginHelper.getUserId());
        momentsReply.setMomentsId(bo.getId());
        momentsReply.setContent(bo.getContent());
        apiMomentsReplyMapper.insert(momentsReply);

        if (!LoginHelper.getPlatformId().equals(moments.getPlatformId())) {
            AppUserExt appUserExt = appUserExtMapper.selectById(LoginHelper.getUserId());
            PushMessage.sendTextSingleSysSquare(
                    moments.getPlatformId(),
                    PrivateMsg.builder()
                            .content("您收到一条新的动态回复:" + bo.getContent())
                            .nickname(appUserExt.getNickName())
                            .headUrl(appUserExt.getHeadUrl())
                            .id(appUserExt.getId())
                            .platformId(LoginHelper.getPlatformId())
                            .build());
        }
    }

    /**
     * 回复回复
     *
     * @author 老张
     * @param bo
     */
    @Override
    public void replyReply(MomentsReplyBo bo) {
        MomentsReply momentsReply = apiMomentsReplyMapper.selectById(bo.getId());
        if (momentsReply == null) {
            throw AppServiceException.paramException("动态回复未找到");
        }
        checkKeyWord(bo.getContent());
        MomentsReply momentsReplyInsert = new MomentsReply();
        momentsReplyInsert.setPlatformId(LoginHelper.getPlatformId());
        momentsReplyInsert.setUserId(LoginHelper.getUserId());
        momentsReplyInsert.setMomentsId(momentsReply.getMomentsId());
        momentsReplyInsert.setReplyId(momentsReply.getId());
        momentsReplyInsert.setContent(bo.getContent());
        apiMomentsReplyMapper.insert(momentsReplyInsert);

        if (!LoginHelper.getPlatformId().equals(momentsReply.getPlatformId())) {
            AppUserExt appUserExt = appUserExtMapper.selectById(LoginHelper.getUserId());
            PushMessage.sendTextSingleSysSquare(
                    momentsReply.getPlatformId(),
                    PrivateMsg.builder()
                            .content("您收到一条新的回复:" + bo.getContent())
                            .nickname(appUserExt.getNickName())
                            .headUrl(appUserExt.getHeadUrl())
                            .id(appUserExt.getId())
                            .platformId(LoginHelper.getPlatformId())
                            .build());
        }
    }

    /**
     * 回复列表
     *
     * @author 老张
     * @param bo
     * @return
     */
    @Override
    public TableDataInfo<ReplyVo> replyList(ReplyListBo bo) {
        // TODO 查看自己的回复列表 可以显示所有人的回复，但是别人只能看到自己和作者的回复
        Moments moments = apiMomentsMapper.selectById(bo.getId());
        if (moments == null) {
            throw AppServiceException.paramException("动态未找到");
        }
        Page<ReplyVo> vos =
                apiMomentsMapper.replyList(
                        bo.build(),
                        bo,
                        LoginHelper.getUserId(),
                        // 动态发布者Id
                        moments.getUserId());
        return TableDataInfo.build(vos);
    }

    /**
     * 回复详情列表
     *
     * @author 老张
     * @param bo
     * @return
     */
    @Override
    public TableDataInfo<ReplyVo> replyDetailList(ReplyListBo bo) {
        MomentsReply momentsReply = apiMomentsReplyMapper.selectById(bo.getId());
        if (momentsReply == null) {
            throw AppServiceException.paramException("动态回复未找到");
        }
        Moments moments = apiMomentsMapper.selectById(momentsReply.getMomentsId());
        if (moments == null) {
            throw AppServiceException.paramException("动态未找到");
        }
        Page<ReplyVo> vos =
                apiMomentsMapper.replyDetailList(
                        bo.build(),
                        momentsReply.getMomentsId(),
                        bo.getId(),
                        moments.getUserId(),
                        LoginHelper.getUserId());
        return TableDataInfo.build(vos);
    }

    /**
     * 审查关键字
     * @author 老张
     */
    @SneakyThrows
    private void checkKeyWord(String content){
        Set<String> badWords =
            sensitiveWordCheck
                .get(CacheConstants.SENSITIVE_WORD)
                .getBadWords(content);
        if (badWords.size() > 0) {
            throw AppServiceException.paramException("不允许发送关键字:" + badWords.toString());
        } else {
            boolean checkAgain = BadWordDetectorUtils.checkAgain(content);
            if (checkAgain) {
                throw AppServiceException.paramException("文本包含不允许发送的关键词");
            }
        }
    }
}
